home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1996 February / EnigmA AMIGA RUN 04 (1996)(G.R. Edizioni)(IT)[!][issue 1996-02][Skylink CD III].iso / earcd / comm2 / termsorc.lha / Extras / Source / gtlayout-source.lha / LTP_LayoutMenu.c < prev    next >
C/C++ Source or Header  |  1995-09-24  |  10KB  |  424 lines

  1. /*  GadTools layout toolkit
  2. **
  3. **  Copyright © 1993-1995 by Olaf `Olsen' Barthel
  4. **  Freely distributable.
  5. **
  6. **  :ts=4
  7. */
  8.  
  9. #include "gtlayout_global.h"
  10.  
  11. #ifdef DO_MENUS
  12.  
  13.     /* LTP_LayoutMenu(RootMenu *Root,WORD ExtraFront,WORD ExtraSpace):
  14.      *
  15.      *    Layout the menus, menu items and submenu items.
  16.      */
  17.  
  18. BOOLEAN __regargs
  19. LTP_LayoutMenu(RootMenu *Root,WORD ExtraFront,WORD ExtraSpace)
  20. {
  21.     WORD        MenuLeft,
  22.                 ItemTop,
  23.                 ItemWidth,
  24.                 ItemShift,
  25.                 CommandWidth,
  26.                 Width;
  27.  
  28.     MenuNode    *Menu;
  29.     ItemNode    *Item,*FirstItem = NULL,*LastItem;
  30.  
  31.     BOOLEAN        Correction;
  32.  
  33.         // That one's simple
  34.  
  35.     for(MenuLeft = ExtraFront, Menu = (MenuNode *)Root -> MenuList . mlh_Head ; Menu -> Node . mln_Succ ; Menu = (MenuNode *)Menu -> Node . mln_Succ)
  36.     {
  37.         Menu -> Menu . LeftEdge = MenuLeft;
  38.  
  39.         MenuLeft += Menu -> Menu . Width + ExtraSpace;
  40.     }
  41.  
  42.         // Now run down the list of items
  43.  
  44.     for(Item = (ItemNode *)Root -> ItemList . mlh_Head ; Item -> Node . mln_Succ ; Item = (ItemNode *)Item -> Node . mln_Succ)
  45.     {
  46.             // Hit a submenu item?
  47.  
  48.         if(Item -> Flags & ITEMF_FirstSub)
  49.         {
  50.             ItemNode    *FirstSub,*LastSub,*Sub;
  51.             WORD         SubTop            = 0,
  52.                          SubWidth        = 0;
  53.             WORD         CommandWidth    = 0;
  54.  
  55.                 // This is where we started
  56.  
  57.             FirstSub = Item;
  58.  
  59.                 // Now determine the widest entry and
  60.                 // line them up below one another
  61.  
  62.             for(Sub = FirstSub ; Sub -> Node . mln_Succ && (Sub -> Flags & ITEMF_IsSub) ; Sub = (ItemNode *)Sub -> Node . mln_Succ)
  63.             {
  64.                 LastSub = Sub;
  65.  
  66.                 if(Sub -> Item . Width > SubWidth)
  67.                     SubWidth = Sub -> Item . Width;
  68.  
  69.                 if((Width = LTP_GetCommandWidth(Root,Sub)) > CommandWidth)
  70.                     CommandWidth = Width;
  71.  
  72.                 Sub -> Item . TopEdge = SubTop;
  73.  
  74.                 SubTop += Sub -> Item . Height;
  75.             }
  76.  
  77.             SubWidth += 4 + CommandWidth;
  78.  
  79.                 // In the second pass, make all entries
  80.                 // use the same width
  81.  
  82.             for(Sub = FirstSub ; ; Sub = (ItemNode *)Sub -> Node . mln_Succ)
  83.             {
  84.                     // Indent the entries that need it
  85.  
  86.                 if(Sub -> Item . Flags & CHECKIT)
  87.                     ((struct IntuiText *)Sub -> Item . ItemFill) -> LeftEdge += 2 + Root -> CheckWidth;
  88.  
  89.                 Sub -> Item . Width = SubWidth;
  90.  
  91.                     // Adapt the separator bar size
  92.  
  93.                 if(Sub -> Flags & ITEMF_IsBar)
  94.                     ((struct Image *)Sub -> Item . ItemFill) -> Width = Sub -> Item . Width - 4;
  95.                 else
  96.                 {
  97.                         // Take care of command keys
  98.  
  99.                     if(Sub -> Flags & ITEMF_Command)
  100.                     {
  101.                         struct IntuiText *Command = ((struct IntuiText *)Sub -> Item . ItemFill) -> NextText;
  102.  
  103.                         Command -> LeftEdge = Sub -> Item . Width - (IntuiTextLength(Command) + 2);
  104.                     }
  105.                 }
  106.  
  107.                     // In the next iteration, continue after the last
  108.                     // submenu item
  109.  
  110.                 if(Sub == LastSub)
  111.                 {
  112.                     Item = Sub;
  113.  
  114.                     break;
  115.                 }
  116.             }
  117.  
  118.             DB(kprintf("last sub |%s|\n",((struct IntuiText *)Item -> Item . ItemFill) -> IText));
  119.         }
  120.         else
  121.         {
  122.                 // Start a new menu?
  123.  
  124.             if(!FirstItem)
  125.             {
  126.                     // This is where we started
  127.  
  128.                 FirstItem = Item;
  129.  
  130.                     // Reset the data
  131.  
  132.                 ItemTop = ItemWidth = ItemShift = CommandWidth = 0;
  133.             }
  134.  
  135.                 // Line up the entries in a column
  136.  
  137.             Item -> Item . TopEdge = ItemTop;
  138.  
  139.             ItemTop += Item -> Item . Height;
  140.  
  141.                 // Search for the widest entry
  142.  
  143.             if(Item -> Item . Width > ItemWidth)
  144.                 ItemWidth = Item -> Item . Width;
  145.  
  146.                 // Search for the widest command sequence
  147.  
  148.             if((Width = LTP_GetCommandWidth(Root,Item)) > CommandWidth)
  149.                 CommandWidth = Width;
  150.  
  151.                 // This is for submenu items which will get
  152.                 // indented by this amount
  153.  
  154.             if(Item -> Item . Width > ItemShift)
  155.                 ItemShift = Item -> Item . Width;
  156.         }
  157.  
  158.             // Is this the last item for this menu?
  159.  
  160.         if(Item -> Flags & ITEMF_LastItem)
  161.         {
  162.             ItemWidth += 4 + CommandWidth;
  163.  
  164.                 // Restart and layout all the items in this menu
  165.  
  166.             for(Item = FirstItem ; Item -> Node . mln_Succ ; Item = (ItemNode *)Item -> Node . mln_Succ)
  167.             {
  168.                     // Indent submenu items
  169.  
  170.                 if(Item -> Flags & ITEMF_IsSub)
  171.                     Item -> Item . LeftEdge += ItemShift + 6;
  172.                 else
  173.                 {
  174.                         // Indent items as necessary
  175.  
  176.                     if(Item -> Item . Flags & CHECKIT)
  177.                         ((struct IntuiText *)Item -> Item . ItemFill) -> LeftEdge += 2 + Root -> CheckWidth;
  178.  
  179.                     Item -> Item . Width = ItemWidth;
  180.  
  181.                         // Adapt the separator bar size
  182.  
  183.                     if(Item -> Flags & ITEMF_IsBar)
  184.                         ((struct Image *)Item -> Item . ItemFill) -> Width = Item -> Item . Width - 4;
  185.                     else
  186.                     {
  187.                             // Take care of submenu item indicators and
  188.                             // command sequences
  189.  
  190.                         if(Item -> Flags & (ITEMF_Command | ITEMF_HasSub))
  191.                         {
  192.                             struct IntuiText *Command = ((struct IntuiText *)Item -> Item . ItemFill) -> NextText;
  193.  
  194.                             Command -> LeftEdge = Item -> Item . Width - (IntuiTextLength(Command) + 2);
  195.                         }
  196.                     }
  197.                 }
  198.  
  199.                     // Abort if this is the last item for this menu
  200.  
  201.                 if(Item -> Flags & ITEMF_LastItem)
  202.                     break;
  203.             }
  204.  
  205.             DB(kprintf("last item |%s|\n",((struct IntuiText *)Item -> Item . ItemFill) -> IText));
  206.  
  207.                 // The next iteration will start a new menu
  208.  
  209.             FirstItem = NULL;
  210.         }
  211.     }
  212.  
  213.         // Calculate the effective positions
  214.  
  215.     LTP_AdjustMenuPosition(Root);
  216.  
  217.     Correction = FALSE;
  218.  
  219.         // We start by chopping down the menus
  220.  
  221.     for(Item = (ItemNode *)Root -> ItemList . mlh_Head ; Item -> Node . mln_Succ ; Item = (ItemNode *)Item -> Node . mln_Succ)
  222.     {
  223.             // That's where we start
  224.  
  225.         if(!FirstItem)
  226.             FirstItem = Item;
  227.  
  228.             // Skip submenu items
  229.  
  230.         if(!(Item -> Flags & ITEMF_IsSub))
  231.             LastItem = Item;
  232.  
  233.             // Did we reach the end of the menu?
  234.  
  235.         if(Item -> Flags & ITEMF_LastItem)
  236.         {
  237.             DB(kprintf("chopping |%s| -> |%s|\n",((struct IntuiText *)FirstItem -> Item . ItemFill) -> IText,((struct IntuiText *)LastItem -> Item . ItemFill) -> IText));
  238.  
  239.                 // Chop down the menus
  240.  
  241.             Correction |= LTP_CorrectItemList(Root,FirstItem,LastItem);
  242.  
  243.             FirstItem = NULL;
  244.         }
  245.     }
  246.  
  247.     if(Correction)
  248.     {
  249.         Correction = FALSE;
  250.  
  251.             // Recalculate the positions
  252.  
  253.         LTP_AdjustMenuPosition(Root);
  254.     }
  255.  
  256.         // Next we shift the menus around to make them fit
  257.  
  258.     for(Menu = (MenuNode *)Root -> MenuList . mlh_Head ; Menu -> Node . mln_Succ ; Menu = (MenuNode *)Menu -> Node . mln_Succ)
  259.     {
  260.         MenuLeft = Menu -> Menu . LeftEdge + 4 + Menu -> Width + 4;
  261.  
  262.             // Does it cross the right screen border?
  263.  
  264.         if(MenuLeft > Root -> Screen -> Width)
  265.         {
  266.                 // Is the menu wider than the screen?
  267.  
  268.             if(4 + Menu -> Width + 4 > Root -> Screen -> Width)
  269.             {
  270.                 DB(kprintf("too wide\n"));
  271.                 return(FALSE);
  272.             }
  273.             else
  274.             {
  275.                 WORD Left = MenuLeft - Root -> Screen -> Width + 1;
  276.  
  277.                     // Move up
  278.  
  279.                 for(Item = (ItemNode *)((ULONG)Menu -> Menu . FirstItem - sizeof(struct MinNode)) ; Item -> Node . mln_Succ ; Item = (ItemNode *)Item -> Node . mln_Succ)
  280.                 {
  281.                     if(!(Item -> Flags & ITEMF_IsSub))
  282.                         Item -> Item . LeftEdge -= Left;
  283.  
  284.                     if(Item -> Flags & ITEMF_LastItem)
  285.                         break;
  286.                 }
  287.  
  288.                 Correction = TRUE;
  289.             }
  290.         }
  291.     }
  292.  
  293.     if(Correction)
  294.     {
  295.         Correction = FALSE;
  296.  
  297.             // Recalculate the positions
  298.  
  299.         LTP_AdjustMenuPosition(Root);
  300.     }
  301.  
  302.         // Now deal with the submenus
  303.  
  304.     for(Item = (ItemNode *)Root -> ItemList . mlh_Head ; Item -> Node . mln_Succ ; Item = (ItemNode *)Item -> Node . mln_Succ)
  305.     {
  306.             // Only submenu items, please
  307.  
  308.         if(Item -> Flags & ITEMF_FirstSub)
  309.         {
  310.             ItemNode *Here;
  311.  
  312.                 // Find the first and the last entry
  313.  
  314.             for(Here = Item ; Here -> Node . mln_Succ ; Here = (ItemNode *)Here -> Node . mln_Succ)
  315.             {
  316.                 if(!(Here -> Flags & ITEMF_IsSub))
  317.                     break;
  318.                 else
  319.                     LastItem = Here;
  320.             }
  321.  
  322.             DB(kprintf("2) chopping |%s| -> |%s|\n",((struct IntuiText *)Item -> Item . ItemFill) -> IText,((struct IntuiText *)LastItem -> Item . ItemFill) -> IText));
  323.  
  324.                 // Chop down the submenus
  325.  
  326.             Correction |= LTP_CorrectItemList(Root,Item,LastItem);
  327.         }
  328.     }
  329.  
  330.     if(Correction)
  331.     {
  332.         Correction = FALSE;
  333.  
  334.         LTP_AdjustMenuPosition(Root);
  335.     }
  336.  
  337.         // Almost finished, now shift the submenus around
  338.  
  339.     for(Item = (ItemNode *)Root -> ItemList . mlh_Head ; Item -> Node . mln_Succ ; Item = (ItemNode *)Item -> Node . mln_Succ)
  340.     {
  341.             // Did we hit a submenu?
  342.  
  343.         if(Item -> Flags & ITEMF_HasSub)
  344.         {
  345.             ItemNode *Here = (ItemNode *)((ULONG)Item -> Item . SubItem - sizeof(struct MinNode));
  346.  
  347.                 // Does this one also cross the right screen border?
  348.  
  349.             if((MenuLeft = Here -> Left + 4 + Here -> Item . Width + 4) > Root -> Screen -> Width)
  350.             {
  351.                 WORD Left = MenuLeft - Root -> Screen -> Width;
  352.  
  353.                     // This shouldn't be wider than the screen, but...
  354.  
  355.                 if(Here -> Left - Left < Item -> Left + 10)
  356.                 {
  357.                     DB(kprintf("sub too wide\n"));
  358.                     return(FALSE);
  359.                 }
  360.                 else
  361.                 {
  362.                     DB(kprintf("3) shifting...\n"));
  363.  
  364.                         // Shift the menu around
  365.  
  366.                     do
  367.                     {
  368.                         if(!(Here -> Flags & ITEMF_IsSub))
  369.                             break;
  370.                         else
  371.                         {
  372.                             Here -> Item . LeftEdge -= Left;
  373.  
  374.                             Correction = TRUE;
  375.  
  376.                             if(Here -> Flags & ITEMF_LastItem)
  377.                                 break;
  378.  
  379.                             Here = (ItemNode *)Here -> Node . mln_Succ;
  380.                         }
  381.                     }
  382.                     while(Here -> Node . mln_Succ);
  383.                 }
  384.             }
  385.         }
  386.     }
  387.  
  388.         // The last step; see if the alignment stuff worked
  389.  
  390.     if(Correction)
  391.         LTP_AdjustMenuPosition(Root);
  392.  
  393.         // First check the menus
  394.  
  395.     for(Menu = (MenuNode *)Root -> MenuList . mlh_Head ; Menu -> Node . mln_Succ ; Menu = (MenuNode *)Menu -> Node . mln_Succ)
  396.     {
  397.             // Does it cross the screen borders?
  398.  
  399.         if((MenuLeft = Menu -> Menu . LeftEdge + 4 + Menu -> Width + 4) > Root -> Screen -> Width || Menu -> Menu . LeftEdge < 0)
  400.             return(FALSE);
  401.     }
  402.  
  403.         // Now check the submenus
  404.  
  405.     for(Item = (ItemNode *)Root -> ItemList . mlh_Head ; Item -> Node . mln_Succ ; Item = (ItemNode *)Item -> Node . mln_Succ)
  406.     {
  407.             // Did we hit a submenu?
  408.  
  409.         if(Item -> Flags & ITEMF_HasSub)
  410.         {
  411.             ItemNode *Here = (ItemNode *)((ULONG)Item -> Item . SubItem - sizeof(struct MinNode));
  412.  
  413.             if(Here -> Left + Here -> Width > Root -> Screen -> Width)
  414.                 return(FALSE);
  415.         }
  416.     }
  417.  
  418.     LTP_FillMenu(&Root -> Menu);
  419.  
  420.     return(TRUE);
  421. }
  422.  
  423. #endif    /* DO_MENUS */
  424.